
#include <iostream>
#include <iomanip>
#include <cmath>
#include <pthread.h>

using namespace std;
double **A, **X;
const double eps = 1e-12;
  class temp1
{
public:
    int s;
    int i;
    int k;
    double **X;
    double **A;
};
void* thread1(void *ptr)
{
    temp1* T1=(temp1*)ptr;
    T1->s=0;
     for(int j = 0; j < T1->i; j++)
         T1->s += T1->A[T1->i][j] * T1->X[j][T1->k];

    T1->X[T1->i][T1->k] -= T1->s;

}

// Funkcja dokonuje rozkładu LU macierzy A

bool ludist(int n, double ** A)
{
  int i,j,k;

  for(k = 0; k < n - 1; k++)
  {
    if(fabs(A[k][k]) < eps) return false;

    for(i = k + 1; i < n; i++)
      A[i][k] /= A[k][k];

    for(i = k + 1; i < n; i++)
      for(j = k + 1; j < n; j++)
        A[i][j] -= A[i][k] * A[k][j];
  }

  return true;
}

// Funkcja wyznacza wektor X na podstawie A i X[i]

bool lusolve(int k, int n, double ** A, double ** X)
{
  int    i,j;
  double s;
 temp1 *t1= new temp1();
t1->A=A;
 t1->X=X;
  t1->s=s;
  t1->k=k;
  pthread_t *watki= new pthread_t[n];
  for(i = 1; i < n; i++)
  {
      t1->i=i;
      pthread_create(&watki[i-1],NULL,thread1,(void*)t1);
 /* s = 0;

    for(j = 0; j < i; j++) s += A[i][j] * X[j][k];

    X[i][k] -= s;
   */
// thread1((void*)t1);
  }

  if(fabs(A[n-1][n-1]) < eps) return false;

  X[n-1][k] /= A[n-1][n-1];

  for(i = n - 2; i >= 0; i--)
  {
    s = 0;

    for(j = i + 1; j < n; j++) s += A[i][j] * X[j][k];

    if(fabs(A[i][i]) < eps) return false;

    X[i][k] = (X[i][k] - s) / A[i][i];
  }

  return true;
}

// Program główny

int  main()
{
  
  int n,i,j;
  bool ok;

  cout << setprecision(5) << fixed;

  // odczytujemy wymiar macierzy A

  cin >> n;

  // tworzymy macierze A i X

  A = new double * [n];
  X = new double * [n];

  for(i = 0; i < n; i++)
  {
    A[i] = new double[n];
    X[i] = new double[n];
  }

  // odczytujemy dane dla macierzy A

  for(i = 0; i < n; i++)
    for(j = 0; j < n; j++) cin >> A[i][j];

  // wykonujemy rozkład LU macierzy A

  if(ludist(n,A))
  {

  // tworzymy macierz jednostkową w X

    for(i = 0; i < n; i++)
    {
      for(j = 0; j < n; j++) X[i][j] = 0;
      X[i][i] = 1;
    }

  // Wyznaczamy kolejne kolumny macierzy odwrotnej w X

    ok = true;
    for(i = 0; i < n; i++)
      if(! lusolve(i,n,A,X))
      {
        ok = false;
        break;
      }
  }
  else ok = false;

  // jeśli obliczenia się powiodły, wyświetlamy X

  if(ok)
  {
    for(i = 0; i < n; i++)
    {
      for(j = 0; j < n; j++)
        cout << setw(10) << X[i][j] << " ";
      cout << endl;
    }
  }
  else cout << "DZIELNIK ZERO\n";

  // usuwamy macierze z pamięci

  for(i = 0; i < n; i++)
  {
    delete [] A[i];
    delete [] X[i];
  }
  delete [] A;
  delete [] X;

  return 0;
}


